#include "MessageSystem.h"
#include "../Managers/VIN_ObjectManager.h"
#include "../Managers/ParticleManager.h"
#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../Core/CParticleEmitter.h"
#include "../Game Objects/CRangedEnemy.h"
#include "../Game Objects/CMeleeEnemy.h"
#include "../Game Objects/CMoneyBag.h"
#include "../Game Objects/CRock.h"
#include "../Game Objects/CProjectile.h"
#include "../Game Objects/CExplodingEnemy.h"
#include "../managers/vin_soundmanager.h"

MessageSystem* MessageSystem::GetInstance(void)
{
	static MessageSystem instance;
	return &instance;
}

void MessageSystem::SendNewMessage(CBaseMessage* message)
{
	this->messageQueue.addHead(message);
}

void MessageSystem::ClearMessages()
{
	SLLIter<CBaseMessage*> iter(messageQueue);

	for(iter.begin(); !iter.checkifvalid(); ++iter)
	{
		delete iter.current();
	}

	this->messageQueue.clear();
}

void MessageSystem::Init()
{
	staticImages[IMAGE_MONEYBAG]	= -1;
	staticImages[IMAGE_MONEYBAG]	= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/money_bag.png");
	staticImages[IMAGE_PIXEL]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Pixel.png");	

	staticImages[IMAGE_BUTTON]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/HUDButton.png");
	staticImages[IMAGE_HAND]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/HandButton.png");
	staticImages[IMAGE_ROCK]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Fat Tallnut.png");
	staticImages[IMAGE_KOFFING]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Koffing.png");
	staticImages[IMAGE_POT]			= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Pot.png");
	staticImages[IMAGE_BALLISTA]	= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Ballista.png");
	staticImages[IMAGE_BOW]			= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Archer.png");

	staticImages[IMAGE_ARROW]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/arrow.png");
	staticImages[IMAGE_BOULDER]		= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/boulder.png");
	staticImages[IMAGE_BALLISTA_ARROW] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/ballista arrow.png");

	staticImages[IMAGE_WALNUT]	= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Tallnut1.png");
	staticImages[IMAGE_WALNUT2]	= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Tallnut2.png");
	staticImages[IMAGE_WALNUT3]	= CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Tallnut3.png");

	staticImages[IMAGE_PLAYER_ARROW] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/playerArrow.png");
	staticImages[IMAGE_CASTLE1] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/castle1.png");
	staticImages[IMAGE_CASTLE2] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/castle2.png");
	staticImages[IMAGE_CASTLE3] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/castle3.png");

	staticImages[IMAGE_PARTICLEPIC] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/Particles/ParticlePic2.png");
	
	staticImages[IMAGE_SHADOW] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Shadow.png");

	staticImages[IMAGE_SPILL] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Spill.png");
	staticImages[IMAGE_SPLAT] = CSGD_TextureManager::GetInstance()->LoadTexture("resources/graphics/Splat.png");

}

void MessageSystem::Shutdown()
{
	for(int i = 0; i < MAXSTATICIMAGES; ++i)
	{
		CSGD_TextureManager::GetInstance()->UnloadTexture(staticImages[i]);
	}
	ClearMessages();
}

void MessageSystem::ProcessMessages()
{
	SLLIter<CBaseMessage*> iter(messageQueue);

	for(iter.begin(); !iter.checkifvalid(); ++iter)
	{
		MessageProc(iter.current());
	}

	ClearMessages();
}

void MessageSystem::MessageProc(CBaseMessage* message)
{
	switch(message->GetMessageType())
	{
	case MSG_CREATE_RANGED:
		{
			CCreateRangedEnemyMessage* rangedMsg = (CCreateRangedEnemyMessage*)message;

			CRangedEnemy* newEnemy = new CRangedEnemy(rangedMsg->GetType());
			newEnemy->SetAlive(true);
			newEnemy->SetPosX(rangedMsg->GetPosX());
			newEnemy->SetPosY(rangedMsg->GetPosY());
			newEnemy->SetRangedType(rangedMsg->GetType());
			if(rangedMsg->GetType() == ENEMY_ARCHER )
			{
				newEnemy->SetPower(15 + (15*rangedMsg->GetCurrWave()));
				newEnemy->SetRange(150.0f + (50.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetHP(30.0f + (15.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetWeight(15 + 5 * rangedMsg->GetCurrWave());
				newEnemy->SetShadowScale(0.75f);
				newEnemy->SetShadowXOffset(-5);
				newEnemy->SetSpeed(0.8f);
			}
			else if(rangedMsg->GetType() == FRIENDLY_ARCHER)
			{
				newEnemy->SetFriendly(true);
				newEnemy->SetLanded(true);
				newEnemy->SetPower(5 + (5*rangedMsg->GetCurrWave()));
				newEnemy->SetRange(200.0f + (50.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetHP(30.0f + (5.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetWeight(15 + 5 * rangedMsg->GetCurrWave());
				newEnemy->SetShadowScale(0.75f);
				newEnemy->SetSpeed(0.0f);
				newEnemy->flip = true;
			}
			else if(rangedMsg->GetType() == ENEMY_CATAPULT)
			{
				newEnemy->SetPower(100 + (25*rangedMsg->GetCurrWave()));
				newEnemy->SetRange(150 + (25.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetHP(50 + (15.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetWeight(65 + 5 * rangedMsg->GetCurrWave());
				newEnemy->SetShadowScale(3.0f);
				newEnemy->SetShadowYOffset(20);
				newEnemy->SetShadowXOffset(-50);
				newEnemy->SetSpeed(0.3f);
			}
			else if(rangedMsg->GetType() == ENEMY_TREBUCHET)
			{
				newEnemy->SetPower(150 + (50*rangedMsg->GetCurrWave()));
				newEnemy->SetRange(50 + (25.0f*((float)rangedMsg->GetCurrWave())));
				newEnemy->SetHP(75 + (15*((float)rangedMsg->GetCurrWave())));				
				newEnemy->SetWeight(80 + 5 * rangedMsg->GetCurrWave());
				newEnemy->SetShadowScale(3.5f);
				newEnemy->SetShadowYOffset(20);
				newEnemy->SetShadowXOffset(-50);
				newEnemy->SetSpeed(0.15f);
			}
			
			newEnemy->SetBaseHP(newEnemy->GetHP());
			
			VIN_ObjectManager::GetInstance()->AddObject(0,newEnemy);

			newEnemy->Release();
		}
		break;
	case MSG_CREATE_MELEE:
		{
			CCreateMeleeEnemyMessage* meleeMsg = (CCreateMeleeEnemyMessage*)message;

			CMeleeEnemy* newEnemy = new CMeleeEnemy(meleeMsg->GetType());
			newEnemy->SetAlive(true);

			newEnemy->SetPosX(meleeMsg->GetPosX());
			newEnemy->SetPosY(meleeMsg->GetPosY());

			if(meleeMsg->GetType() == ENEMY_CLERIC)
			{
				newEnemy->SetPower(25 + (25*meleeMsg->GetCurrWave()));
				newEnemy->SetRange(150.0f + (50.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetHP(35.0f + (15.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetSpeed(0.3f);
				newEnemy->SetShadowScale(1.0f);
				newEnemy->SetShadowYOffset(-4);
				newEnemy->SetShadowXOffset(-10);
				newEnemy->SetWeight(50 + 5 * meleeMsg->GetCurrWave());
			}
			else if(meleeMsg->GetType() == ENEMY_DWARF)
			{
				newEnemy->SetPower(20 + (15*meleeMsg->GetCurrWave()));
				newEnemy->SetRange(150.0f + (50.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetHP(30.0f + (15.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetSpeed(0.6f);
				newEnemy->SetShadowScale(0.9f);
				newEnemy->SetShadowYOffset(0);
				newEnemy->SetShadowXOffset(-10);
				newEnemy->SetWeight(40 + 5 * meleeMsg->GetCurrWave());
			}
			else if(meleeMsg->GetType() == ENEMY_FIGHTER)
			{
				newEnemy->SetPower(15 + (5*meleeMsg->GetCurrWave()));
				newEnemy->SetRange(150.0f + (50.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetHP(30.0f + (10.0f*((float)meleeMsg->GetCurrWave())));
				newEnemy->SetSpeed(0.7f);
				newEnemy->SetShadowScale(1.2f);
				newEnemy->SetShadowYOffset(-8);
				newEnemy->SetShadowXOffset(-13);
				newEnemy->SetWeight(30 + 5 * meleeMsg->GetCurrWave());
			}



			newEnemy->SetBaseHP(newEnemy->GetHP());

			VIN_ObjectManager::GetInstance()->AddObject(0,newEnemy);

			newEnemy->Release();
		}
		break;
	case MSG_CREATE_EXPLODING:
		{
			CCreateExplodingEnemyMessage* explodingMsg = (CCreateExplodingEnemyMessage*)message;

			CExplodingEnemy* newEnemy = new CExplodingEnemy();
			
			newEnemy->SetPosX(explodingMsg->GetPosX());
			newEnemy->SetPosY(explodingMsg->GetPosY());

			newEnemy->SetPower(50 + (15*explodingMsg->GetCurrWave()));
			newEnemy->SetRange(150.0f + (50.0f*((float)explodingMsg->GetCurrWave())));
			newEnemy->SetHP(60.0f + (15.0f*((float)explodingMsg->GetCurrWave())));
			newEnemy->SetBaseHP(newEnemy->GetHP());
			newEnemy->SetSpeed(65.0f + (8.0f*((float)explodingMsg->GetCurrWave())));
			newEnemy->SetWeight(25 + 5 * explodingMsg->GetCurrWave());

			VIN_ObjectManager::GetInstance()->AddObject(0,newEnemy);

			newEnemy->Release();
		}
		break;
	case MSG_CREATE_MONEYBAG:
		{
			CCreateMoneyBagMessage* moneyMsg = (CCreateMoneyBagMessage*)message;

			CMoneyBag* moneyBag = new CMoneyBag;
			moneyBag->SetPosX(moneyMsg->GetPosX());
			moneyBag->SetPosY(moneyMsg->GetPosY());
			moneyBag->SetVelX(moneyMsg->GetVelX());
			moneyBag->SetVelY(moneyMsg->GetVelY());
			moneyBag->SetValue(moneyMsg->GetCurrWave()*4);

			moneyBag->SetImageID(staticImages[IMAGE_MONEYBAG]);

			VIN_ObjectManager::GetInstance()->AddObject(2,moneyBag);

			moneyBag->Release();
		}
		break;
	case MSG_CREATE_ROCK:
		{
			CCreateRockMessage* RockMsg = (CCreateRockMessage*)message;

			CRock* Rock = new CRock;
			Rock->SetPosX(RockMsg->GetPosX());
			Rock->SetPosY(RockMsg->GetPosY());
			Rock->SetWidth(CSGD_TextureManager::GetInstance()->GetTextureWidth(Rock->GetImageID()));
			Rock->SetHeight(CSGD_TextureManager::GetInstance()->GetTextureHeight(Rock->GetImageID()));
			Rock->SetMaxHealth((float)(RockMsg->GetCurrLvl()*100));
			Rock->SetHP(Rock->GetMaxHealth());

			Rock->SetImageID(staticImages[IMAGE_ROCK]);
			Rock->SetWidth(CSGD_TextureManager::GetInstance()->GetTextureWidth(Rock->GetImageID()));
			Rock->SetHeight(CSGD_TextureManager::GetInstance()->GetTextureHeight(Rock->GetImageID()));

			VIN_ObjectManager::GetInstance()->AddObject(2,Rock);
			VIN_SoundManager::GetInstance()->PlayRock();

			Rock->Release();
		}
		break;
	case MSG_CREATE_PROJECTILE:
		{
			CCreateProjectileMessage* projectileMsg = (CCreateProjectileMessage*)message;

			CProjectile* projectile = new CProjectile;
			projectile->SetPosX(projectileMsg->GetPosX());
			projectile->SetPosY(projectileMsg->GetPosY());
			projectile->SetVelX(projectileMsg->GetVelX());
			projectile->SetVelY(projectileMsg->GetVelY());

			if(projectileMsg->GetType() == 0)
			{
				projectile->SetImageID(staticImages[IMAGE_ARROW]);
			}
			else if(projectileMsg->GetType() == 1)
			{
				projectile->SetImageID(staticImages[IMAGE_BOULDER]);
			}
			else if(projectileMsg->GetType() == 2)
			{
				projectile->SetImageID(staticImages[IMAGE_PLAYER_ARROW]);
			}
			else if(projectileMsg->GetType() == 3)
			{
				projectile->SetImageID(staticImages[IMAGE_BALLISTA_ARROW]);
				projectile->SetColide(false);
				projectile->SetProjectileScale(0.5f);
			}

			VIN_ObjectManager::GetInstance()->AddObject(2,projectile);

			projectile->Release();
		}
		break;
	case MSG_CREATE_EMITTER:
		{
			CCreateParticleEmitterMessage* emittermsg = (CCreateParticleEmitterMessage*)message;
			CParticleEmitter* newEmitter = ParticleManager::GetInstance()->CreateEmitter(emittermsg->GetType());

			newEmitter->SetEmitterStartPositionX(emittermsg->GetPositionX());
			newEmitter->SetEmitterStartPositionY(emittermsg->GetPositionY());
			newEmitter->SetEmitterStartVelocityX(emittermsg->GetVelocityX());
			newEmitter->SetEmitterStartVelocityY(emittermsg->GetVelocityY());

			ParticleManager::GetInstance()->GetActiveParticles().push_back(newEmitter);
		}
		break;
	case MSG_DESTROY_OBJECT:
		{
			CDestroyObjectMessage* objmsg = (CDestroyObjectMessage*)message;

			VIN_ObjectManager::GetInstance()->RemoveObject( objmsg->GetType(), objmsg->GetObject());
		}
		break;
	}
}